package com.xb.loan.util.qrtz;


import com.xb.loan.util.qrtz.common.Constants;
import com.xb.loan.util.qrtz.listener.TaskListenerSupport;
import com.xb.loan.util.qrtz.task.AbstractCronTask;
import com.xb.loan.util.qrtz.task.AbstractSimpleTask;
import com.xb.loan.util.qrtz.task.AbstractTask;
import com.xb.loan.util.qrtz.task.Task;
import com.xb.loan.util.qrtz.task.impl.CheckMisFireTask;
import org.quartz.*;
import org.quartz.impl.StdScheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

import java.util.Date;
import java.util.Map;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

/**
 * 
 * 任务调度管理器
 * @author hyd
 */

public class TaskScheduleManager implements  ApplicationListener<ApplicationEvent> {

	private Logger logger = LoggerFactory.getLogger(TaskScheduleManager.class);

	private StdScheduler scheduler;
	private TaskListenerSupport taskListenerSupport = new TaskListenerSupport();
	private String defaultGroup = "default";
	/** 任务处理节点ip*/
	private String host;
	/**
	 * 任务丢失触发 最大时间
	 */
	private long misfiretime;

	public long getMisfiretime() {
		return misfiretime;
	}

	public void setMisfiretime(long misfiretime) {
		this.misfiretime = misfiretime;
	}

	public StdScheduler getStdScheduler() {
        return scheduler;
    }
	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public TaskListenerSupport getTaskListenerSupport() {
		return taskListenerSupport;
	}

	public void setTaskListenerSupport(TaskListenerSupport taskListenerSupport) {
		this.taskListenerSupport = taskListenerSupport;
	}

	public void setScheduler(StdScheduler scheduler) {
		this.scheduler = scheduler;
	}

	
	/**
     * 
     * 获取spring上下文
     * @return
     */
	private ApplicationContext getApplicationContext()  {
		try {
            return (ApplicationContext) scheduler.getContext().get(Constants.applicationContext);
        } catch (SchedulerException e) {
            logger.error(e.getMessage(),e);
        }
		return null;
	}
	

	/**
     * 
     * 初始化参数
     * @return
     */
	private void initParams(JobDetail jobDetail, Task task) {
		Map<String, Object> paramsMap = ((AbstractTask) task).getParams();
		if(paramsMap==null)
			return;
		for (String key : paramsMap.keySet()) {
			jobDetail.getJobDataMap().put(key, paramsMap.get(key));
		}
	}
	/**
     * 
     * 调度任务
     * @return
     */
	public boolean shedule(String taskId, Class<? extends Task> clazz, String cron, Map<String, Object> params) {
		Object obj = null;
		if (taskId == null || "".equals(taskId)) {
			return false;
		}

		try {
			obj = clazz.newInstance();
		} catch (Exception e) {
			logger.error("",e);
			return false;
		} 
		
		if (obj instanceof AbstractTask) {
			AbstractTask task = (AbstractTask) obj;
			task.setJobName(taskId);
			task.setParams(params);
		} else {
			return false;
		}

		if (obj instanceof AbstractCronTask) {
			if (cron == null || "".equals(cron))
				return false;
			((AbstractCronTask) obj).setCron_expression(cron);
		}
		return shedule((Task)obj);
	}
	
	public boolean shedule(Task task) {
		return shedule(task, true);
	}

	/**
	 * 
	 * 调度任务
	 * @param replaceExisting
	 * @return
	 */
	public boolean shedule(Task task, boolean replaceExisting) {

		try {
			if (task == null)
				return false;
			((AbstractTask) task).setTaskScheduleManager(this);
			
			if (((AbstractTask) task).getJobName() == null || "".equals(((AbstractTask) task).getJobName())) {
				logger.info("JobName is null or empty");
				return false;
			}

			TriggerKey triggerKey = TriggerKey.triggerKey(((AbstractTask) task).getJobName(),
					((AbstractTask) task).getJobGroup());
			Trigger	trigger = scheduler.getTrigger(triggerKey);
			String Key =task.getTaskEntityId();
			if (trigger != null) {
				logger.info("  trigger  is repetition, Key= [ " + Key + " ]");
				return false;
			}

			JobDetail jobDetail = JobBuilder.newJob(task.getProcessClass())
					.withIdentity(((AbstractTask) task).getJobName(), ((AbstractTask) task).getJobGroup())
					.requestRecovery(((AbstractTask) task).isRequestRecovery()).storeDurably(((AbstractTask)task).isStoreDurably()).build();

			if (scheduler.getJobDetail(jobDetail.getKey()) != null) {
				logger.info(" JobDetail is repetition  key=" + Key + " ]");
				return false;
			}
			try {
				if (replaceExisting)
					taskListenerSupport.fireTaskCreate(task);
			} catch (Exception e) {
			   // logger.error("",e);
			    logger.warn("task  is repetition");
				return false;
			}

			initParams(jobDetail, task);
			if (task instanceof AbstractSimpleTask) {
				AbstractSimpleTask simpleTask = (AbstractSimpleTask) task;
				Date startTime=simpleTask.getStartTime();
                if (startTime == null) {
                    int delay_second = simpleTask.getDelay_second();
                    if (delay_second == 0) delay_second = 1;
                    startTime = DateBuilder.nextGivenSecondDate(null, simpleTask.getDelay_second());
                }
				trigger = newTrigger().withIdentity(simpleTask.getJobName(), simpleTask.getJobGroup())
						.startAt(startTime).build();
			} else if (task instanceof AbstractCronTask) {
				AbstractCronTask cronTask = (AbstractCronTask) task;
				trigger = newTrigger().withIdentity(cronTask.getJobName(), cronTask.getJobGroup())
						.withSchedule(cronSchedule(cronTask.getCron_expression())).build();
			}
			scheduler.scheduleJob(jobDetail, trigger);
			return true;
		} catch (SchedulerException e) {
			logger.error("", e);
		}
		return false;

	}

	/**
	 * 
	 * 重新调度任务
	 * @param task
	 */
	public void reShedule(Task task) {

		TriggerKey triggerKey = TriggerKey.triggerKey(((AbstractTask) task).getJobName(),
				((AbstractTask) task).getJobGroup());
		try {
			scheduler.pauseTrigger(triggerKey);
			scheduler.unscheduleJob(triggerKey);
			scheduler.deleteJob(new JobKey(((AbstractTask) task).getJobName(), ((AbstractTask) task).getJobGroup()));
			shedule(task, false);
		} catch (Exception e) {
			logger.error("", e);
		}
	}

	/**
	 * 
	 * 任务初始化 ，启动哑火任务检测
	 */
	public void init() {
		CheckMisFireTask checkTask = new CheckMisFireTask();
		checkTask.setJobName("checkMisFire");
		checkTask.setCron_expression("0/20 * * ? * * *");
		shedule(checkTask);
	}
	

    public void onApplicationEvent(ApplicationEvent arg0) {

    }
    
    /**
     * 
     * 获取spring bean
     * @param beanId
     * @return
     */
    public <T> T getBean(String beanId) {
        return (T) getApplicationContext().getBean(beanId);
    }
    
    /**    
     * 立即执行一个任务
     * @throws SchedulerException    
     */    
    public void immediateRunTask(String taskName) {

        if (taskName == null || "".equals(taskName))
            return;
        JobKey jobKey = JobKey.jobKey(taskName, defaultGroup);
        TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup());
        if (triggerKey == null) {
            logger.info("taskName=" + taskName + "  doesn’t exist");
            return;
        }
        try {
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            logger.error("", e);
        }
    }
    
    
    
}
